#ifndef PARTICLEMANAGER_H
#define PARTICLEMANAGER_H

#include "Globals.h"
#include "tinyxml\tinyxml.h"

#include "IBaseInterface.h"
#include "SGD_Math.h"
#include "SGD Wrappers\CSGD_Direct3D.h"
#include "SGD Wrappers\CSGD_TextureManager.h"

#include <map>
using std::map;

#include <string>
using std::string;

class ParticleManager : public IBaseInterface
{
private:

	class Emitter
	{
		struct Particle
		{
			float m_fLifeTime;				// How long each particle will live
			float m_fCurrentLife;			// Particle's Age
			float m_fRotation;				// Particle's Rotation
			float m_fScale;					// Particle's Scale
			tVector2D m_vVelocity;			// Particle's X and Y Velocity
			tVector2D m_vCurrentPosition;	// Particle's current X and Y Position
			tVector2D m_vStartPosition;		// Particle's starting X and Y Position
			D3DXCOLOR m_cColor;				// Particle's Color and Alpha
			bool m_bIsAlive;				// Is this particle still alive, when not looping?
		};

		RECT m_rEmitter;			// RECT where it will emit from
		float m_fPositionX;			// Position on the X
		float m_fPositionY;			// Position on the Y
		bool m_bIsLooping;			// Are the particles looping?
		Particle** m_pParticles;	// All the particles
		int m_nSourceBlend;			// The Source Blend
        int m_nDestinationBlend;	// The Destination Blend
        int m_nMaxParticles;		// The maximum amount of particles
        string m_sImageFileName;	// The file name
        int m_nImageID;				// Particle's image ID
        tVector2D m_vGravity;		// Gravitational force
        tVector2D m_vVelocity1;		// Positive Velocity
        tVector2D m_vVelocity2;		// Negative Velocity
        D3DXCOLOR m_cStartColor;	// Starting Color
        D3DXCOLOR m_cEndColor;		// Ending Color
        float m_fStartScale;		// Starting Scale
		float m_fEndScale;			// Ending Scale
        float m_fRotation;			// Partice's rotation
        float m_fMinLifeSpan;		// Minimum Lifespan possible
		float m_fMaxLifeSpan;		// Maximum Lifespan possible
		tVector2D m_vOffset;		// offset from the texture

	public:

		Emitter() { m_vOffset.fX = 0; m_vOffset.fY = 0;}	// Constructor

		void Update(float ElapsedTime)
		{

			m_vOffset.fX = (float)(CSGD_TextureManager::GetInstance()->GetTextureWidth(m_nImageID) >> 1);
			m_vOffset.fY = (float)(CSGD_TextureManager::GetInstance()->GetTextureHeight(m_nImageID) >> 1);

			for (int i = 0; i < m_nMaxParticles; i++)
            {
                m_pParticles[i]->m_fCurrentLife += (float)ElapsedTime;
                
                if(m_fStartScale < m_fEndScale)
                    m_pParticles[i]->m_fScale += m_fStartScale * ElapsedTime;
                else if(m_fStartScale > m_fEndScale)
                    m_pParticles[i]->m_fScale -= m_fStartScale * ElapsedTime;

                m_pParticles[i]->m_fRotation += m_fRotation;
                //m_pParticles[i]->m_vCurrentPosition.fX += m_pParticles[i]->m_vVelocity.fX * ElapsedTime;
                //m_pParticles[i]->m_vCurrentPosition.fX += m_vGravity.fX;
                //m_pParticles[i]->m_vCurrentPosition.fY += m_pParticles[i]->m_vVelocity.fY * ElapsedTime;
                //m_pParticles[i]->m_vCurrentPosition.fY += m_vGravity.fY;
				m_pParticles[i]->m_cColor.r = Lerp(m_cStartColor.r, m_cEndColor.r, (float)m_pParticles[i]->m_fCurrentLife);
				m_pParticles[i]->m_cColor.g = Lerp(m_cStartColor.g, m_cEndColor.g, (float)m_pParticles[i]->m_fCurrentLife);
				m_pParticles[i]->m_cColor.b = Lerp(m_cStartColor.b, m_cEndColor.b, (float)m_pParticles[i]->m_fCurrentLife);
				m_pParticles[i]->m_cColor.a = Lerp(m_cStartColor.a, m_cEndColor.a, (float)m_pParticles[i]->m_fCurrentLife);

                if (m_pParticles[i]->m_fCurrentLife > m_pParticles[i]->m_fLifeTime && m_bIsLooping == true)
                {
                    m_pParticles[i]->m_fLifeTime = float(rand() % ((int)m_fMaxLifeSpan - (int)m_fMinLifeSpan + 1) + (int)m_fMinLifeSpan);
                    m_pParticles[i]->m_fCurrentLife = 0;
                    m_pParticles[i]->m_fScale = m_fStartScale;
                    m_pParticles[i]->m_fRotation = m_fRotation;
					m_pParticles[i]->m_vVelocity.fX = float(rand() % ((int)m_vVelocity1.fX - (int)m_vVelocity2.fX + 1) + (int)m_vVelocity2.fX);
                    m_pParticles[i]->m_vVelocity.fY = float(rand() % ((int)m_vVelocity1.fY - (int)m_vVelocity2.fY + 1) + (int)m_vVelocity2.fY);
                    m_pParticles[i]->m_vCurrentPosition = m_pParticles[i]->m_vStartPosition;
                    m_pParticles[i]->m_cColor = m_cStartColor;
                }
                else if (m_pParticles[i]->m_fCurrentLife > m_pParticles[i]->m_fLifeTime && m_bIsLooping == false)
                {
                     m_pParticles[i]->m_bIsAlive = false;
                }
            }
		}

		void Render(void)
		{
			//CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetRenderState(
			
			for(int i = 0; i < m_nMaxParticles; i++)
			{
				if(m_pParticles[i]->m_bIsAlive == true)
				{
				D3DCOLOR Color = D3DCOLOR_ARGB((int)m_pParticles[i]->m_cColor.a,(int)m_pParticles[i]->m_cColor.r,
					(int)m_pParticles[i]->m_cColor.g,(int)m_pParticles[i]->m_cColor.b);

				CSGD_TextureManager::GetInstance()->Draw(m_nImageID,
					m_pParticles[i]->m_vCurrentPosition.fX,
					m_pParticles[i]->m_vCurrentPosition.fY,
					m_pParticles[i]->m_fScale,m_pParticles[i]->m_fScale,
					0,(m_vOffset.fX * m_pParticles[i]->m_fScale),
					(m_vOffset.fY * m_pParticles[i]->m_fScale),m_pParticles[i]->m_fRotation,
					Color);
				}
			}
		}
		
		// Accessors
		RECT GetRect(void)				{return m_rEmitter;}
		float GetPosX(void)				{return m_fPositionX;}
		float GetPosY(void)				{return m_fPositionY;}
		bool GetLoop(void)				{return m_bIsLooping;}
		int GetSrcBlend(void)			{return m_nSourceBlend;}
		int GetDestBlend(void)			{return m_nDestinationBlend;}
		int GetMaxParticles(void)		{return m_nMaxParticles;}
		tVector2D GetVelocity1(void)	{return m_vVelocity1;}
		tVector2D GetVelocity2(void)	{return m_vVelocity2;}
		D3DXCOLOR GetStartColor(void)	{return m_cStartColor;}
		D3DXCOLOR GetEndColor(void)		{return m_cEndColor;}
		float GetStartScale(void)		{return m_fStartScale;}
		float GetEndScale(void)			{return m_fEndScale;}
		float GetRotation(void)			{return m_fRotation;}
		float GetMinLifeSpan(void)		{return m_fMinLifeSpan;}
		float GetMaxLifeSpan(void)		{return m_fMaxLifeSpan;}
		tVector2D GetOffset(void)		{return m_vOffset;}
		Particle* GetParticles(int index){return m_pParticles[index];}
		string GetImageFile(void)		{return m_sImageFileName;}

		// Mutators
		void SetRectL(long Left)				{m_rEmitter.left = Left;}
		void SetRectR(long Right)				{m_rEmitter.left = Right;}
		void SetRectT(long Top)					{m_rEmitter.left = Top;}
		void SetRectB(long Bottom)				{m_rEmitter.left = Bottom;}
		void SetPosX(float x)					{m_fPositionX = x;}
		void SetPosY(float y)					{m_fPositionY = y;}
		void SetLoop(bool loop)					{m_bIsLooping = loop;}
		void SetSrcBlend(int source)			{m_nSourceBlend = source;}
		void SetDestBlend(int dest)				{m_nDestinationBlend = dest;}
		void SetMaxParticles(int Max)			{m_nMaxParticles = Max;}
		void SetVelocityX1(float velX1)			{m_vVelocity1.fX = velX1;}
		void SetVelocityY1(float velY1)			{m_vVelocity1.fY = velY1;}
		void SetVelocityX2(float velX2)			{m_vVelocity2.fX = velX2;}
		void SetVelocityY2(float velY2)			{m_vVelocity2.fY = velY2;}
		void SetGravityX(float GravX)			{m_vGravity.fX = GravX;}
		void SetGravityY(float GravY)			{m_vGravity.fY = GravY;}
		void SetStartColorR(float R)			{m_cStartColor.r = R;}
		void SetStartColorG(float G)			{m_cStartColor.g = G;}
		void SetStartColorB(float B)			{m_cStartColor.b = B;}
		void SetStartColorA(float A)			{m_cStartColor.a = A;}
		void SetEndColorR(float R)				{m_cEndColor.r = R;}
		void SetEndColorG(float G)				{m_cEndColor.g = G;}
		void SetEndColorB(float B)				{m_cEndColor.b = B;}
		void SetEndColorA(float A)				{m_cEndColor.a = A;}
		void SetStartScale(float startScale)	{m_fStartScale = startScale;}
		void SetEndScale(float endScale)		{m_fEndScale = endScale;}
		void SetRotation(float rotation)		{m_fRotation = rotation;}
		void SetMinLifeSpan(float minlife)		{m_fMinLifeSpan = minlife;}
		void SetMaxLifeSpan(float maxlife)		{m_fMaxLifeSpan = maxlife;}
		void SetOffset(tVector2D offset)		{m_vOffset = offset;}
		void SetFileName(string file)			{m_sImageFileName = file;}
		void SetImageID(int id)					{m_nImageID = id;}
		void SetParticles(int NumofParts)		
		{
			m_pParticles = new Particle*[NumofParts];

			for(int i = 0; i < NumofParts; i++)
			{
				m_pParticles[i] = new Particle();
			}
		}

		void SetLoop(int loop)					
		{
			// if true
			if(loop != 0)
			{
				m_bIsLooping = true;
			}
			// if false
			else if(loop == 0)
			{
				m_bIsLooping = false;
			}
		}

	};

	// contructor
	ParticleManager() {}
	// Trilogy of Evil
	~ParticleManager();
	ParticleManager(const ParticleManager&);
	ParticleManager& operator=(const ParticleManager&);

	map<string,Emitter*> ParticleMap;		// Map for holding each xml file and it's emitter

	int m_nOMGroupID;						// For the enum in the object manager

	string ParticleFile;					// The Paricle File we are loading

	unsigned int m_uiRefCount;				// how many objs have a ptr
											// to me?

public:

	static ParticleManager* GetInstance(void);

	bool Load(string filename);

	void Update(float ElapsedTime);

	void Render(void);

	void AddRef(void);
	void Release(void);

	int GetType(void) {return 0;}
	RECT GetRect() { RECT rect = {0,0,0,0}; return rect;}

	unsigned int  GetOMGroupID() const {return m_nOMGroupID;}		

	bool CheckCollision(IBaseInterface * pBase ) {return false;}

};

#endif